/**
 * XDF Validate 
 * ------------------------------
 * 
 * - 
 * - 
 * 
 * @author 
 */
package model.validator;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Stack;
import java.util.Vector;

import org.xml.sax.Attributes;
import automata.Fsa;
import automata.Label;
import automata.State;

import model.constraints.AbstractConstraint;
import model.constraints.inherited.Configuration;
import model.constraints.inherited.ConfigurationXDF;
import model.constraints.inherited.Inters;
import model.constraints.inherited.configurationSet.ConfigurationSet;
import model.constraints.inherited.configurationSet.ConfigurationSetXDF;
import model.constraints.synthesized.attributes.SyntAttributesAbstract;
import model.constraints.synthesized.attributes.SyntAttributesXDF;

public class XDFValidate  implements ObserverSaxParser, Serializable  {

	private static final long serialVersionUID = 1L;
	private ConfigurationSet confSet1;
	private ConfigurationSetXDF confSetAux;

	private Vector<ConfigurationSet> confVec;
	private Vector<SyntAttributesAbstract> syntVec;

	private Stack<Vector<ConfigurationSet>> stackConf;
	private Stack<Vector<SyntAttributesAbstract>> stackSynt;

	private int posRight;
	private StringBuffer posSt;
	
	private Vector<Hashtable<String, Hashtable<ArrayList<String>, String>>> htVec;
	private Hashtable<String, Hashtable<ArrayList<String>, String>> htContextXfd;
	
	private Vector<Hashtable<String,ArrayList<Inters>>> interVec;
	private Hashtable<String, ArrayList<String>> htErrors;
	private AbstractConstraint absConstraint;
	
	public XDFValidate(AbstractConstraint constraint) {
		absConstraint = constraint;
	}

	public void constructorValidate() {		
		Fsa f = absConstraint.getContextFsa();
		State s = f.get_start_state();
				
		confSet1 =  new ConfigurationSetXDF();
		confSetAux = new ConfigurationSetXDF();
		confVec = new Vector<ConfigurationSet>();
		syntVec = new Vector<SyntAttributesAbstract>();
		stackConf= new Stack<Vector<ConfigurationSet>>();
		stackSynt = new Stack<Vector<SyntAttributesAbstract>>();
		
		confSet1.add(new ConfigurationXDF(s, f, absConstraint));	
				
		confVec = new Vector<ConfigurationSet>();
		confVec.add(confSet1);
		
		
		syntVec = new Vector<SyntAttributesAbstract>();
		syntVec.add(new SyntAttributesXDF());
						
		
		htContextXfd = new Hashtable<String, Hashtable<ArrayList<String>, String>>();
		htVec = new Vector<Hashtable<String, Hashtable<ArrayList<String>, String>>>();			
		htVec.add(htContextXfd);
		
		interVec = new Vector<Hashtable<String,ArrayList<Inters>>>();
		interVec.add(new Hashtable<String,ArrayList<Inters>>());
							
		htErrors = new Hashtable<String, ArrayList<String>>();
		htErrors.put(absConstraint.getNameConstraint(), new ArrayList<String>());//init hash of errors	
							
		posRight = 0;
     	posSt = new StringBuffer("r");
     	
     	stackConf.push(confVec);
     	stackSynt.push(syntVec);
	}	
	
	public void startDocument() {}

	public void endDocument() {}
	
	public void startElement(String localName, String rawName, Attributes attrs) {		
		
		Label l = new Label(rawName);		
		
		Vector<SyntAttributesAbstract> vecSynt = new Vector<SyntAttributesAbstract>();		
		SyntAttributesAbstract syntAtt = new SyntAttributesXDF();
		syntAtt.setNodeName(rawName);
		vecSynt.add(syntAtt);	
		
		//System.out.println("tag: " + rawName);
		
		posSt.append(".");
		posSt.append(posRight);
		posRight = 0;
		
		confVec = (Vector<ConfigurationSet>) stackConf.peek();//remove vector of ConfigurationSet of stackConf
		Vector<ConfigurationSet> vecAux = new Vector<ConfigurationSet>();//this a new vector auxiliary
		
		confSetAux = new ConfigurationSetXDF();
		for (ConfigurationSet configurationSet: confVec) {//for all constraints do:
			confSetAux = (ConfigurationSetXDF) configurationSet.changeConfiguration(l);
			
			System.out.println("***config set" + confSetAux.toString() + "size: " + confSetAux.size());
			vecAux.add(confSetAux);
		}

		stackConf.push(vecAux);//insert vector auxiliary in stackConf		
		stackSynt.push(vecSynt);//insert vector synthesized
				
		//attributes are already leaves, so they are treated here
		int len = attrs.getLength();
		
		if (len > 0){ //A->data			
			for (int i = 0; i < len; i++) {				
				posSt.append(".");
				posSt.append(posRight);
				posRight++;
				String sa = attrs.getQName(i);
				String sb = (String) attrs.getValue(i);
				
				System.out.println("sa: " + sa);
				System.out.println("sb: " + sb);
				
				int j = posSt.lastIndexOf(".");
				
				Label la = new Label(sa);
				vecSynt = (Vector<SyntAttributesAbstract>) stackSynt.pop();
				confVec = (Vector<ConfigurationSet>) stackConf.peek();//get element top of stack without remove
				
				for (int k = 0; k < confVec.size(); k++){ //for all keys do:
					Hashtable<String,ArrayList<Inters>> htIntersXfd = interVec.elementAt(k);
					confSet1 = (ConfigurationSetXDF) confVec.elementAt(k);
					confSetAux = (ConfigurationSetXDF) confSet1.changeConfiguration(la); 
					confSetAux.keyValidationData(vecSynt, k, sb, posSt.substring(0,j), posSt.toString(), rawName, htIntersXfd);
				}
				
				stackSynt.push(vecSynt);
				posSt.delete(j, posSt.length());
			}
		}
	}
	
	
	public void endElement(String localName, String rawName, String chVal) {
		
		//System.out.println("CLOSING Node name:"+rawName + "chVal: " + chVal);
		
		confVec = (Vector<ConfigurationSet>) stackConf.pop();//get lastElement insert of stack
		
		Vector<SyntAttributesAbstract> vecSyntAnt;		
		Vector<SyntAttributesAbstract> vecSynt;
		
	    int j = posSt.lastIndexOf(".");
		posRight = Integer.valueOf(posSt.substring(j+1)).intValue();		
		posRight++;		
		
		if(!chVal.isEmpty()) { //A->data						
			
			vecSynt = (Vector<SyntAttributesAbstract>) stackSynt.pop();	
			vecSyntAnt = (Vector<SyntAttributesAbstract>) stackSynt.pop();
			
			for (int k = 0; k < confVec.size(); k++){ //for all keys do
				confSet1 = (ConfigurationSetXDF) confVec.elementAt(k);
				ConfigurationSetXDF confSetAux = (ConfigurationSetXDF) confSet1;
				Hashtable<String,ArrayList<Inters>> htIntersXfd = interVec.elementAt(k);
				System.out.println("chaval:"+ chVal + " - j:" +  posSt.substring(0,j) + "posSt" +  posSt.toString());
				vecSyntAnt = confSetAux.keyValidationData(vecSyntAnt, k, chVal, posSt.substring(0,j), posSt.toString(), rawName, htIntersXfd);
			}
			
			stackSynt.push(vecSyntAnt);
			
		} else { //A->a1,...,an					
			
			int k;
			
			vecSynt = (Vector<SyntAttributesAbstract>) stackSynt.pop();	
			vecSyntAnt = (Vector<SyntAttributesAbstract>) stackSynt.pop();
			
			for (k = 0; k < confVec.size(); k++){ // for each constraint : appropriate validation
				confSet1 = (ConfigurationSet) confVec.elementAt(k);
				ConfigurationSetXDF confSetAux = (ConfigurationSetXDF) confSet1;
				Hashtable<String, Hashtable<ArrayList<String>, String>> htContextXfd = (Hashtable<String, Hashtable<ArrayList<String>, String>>) htVec.elementAt(k);
				Hashtable<String,ArrayList<Inters>> htIntersXfd = interVec.elementAt(k);				
				SyntAttributesXDF valuesSynt = (SyntAttributesXDF)vecSynt.elementAt(k);
				
		    	vecSyntAnt = confSetAux.keyValidationInNode(vecSyntAnt, k, valuesSynt, posSt.substring(0,j), posSt.toString(), rawName, htContextXfd, htIntersXfd, htErrors);		    
			}

			//System.out.println("Vetor HT:" +htVec.toString());
			//System.out.println("Vetor :" +vecSyntAnt.toString());

			stackSynt.push(vecSyntAnt);	

		}
				
		vecSynt=null;
		posSt.delete(j,posSt.length());
	}
	
	/* Get and Set Methods */

	public void setConstraint(Object constraint) {
		absConstraint = (AbstractConstraint) constraint;
	}
	
	public Object getConstraint(){
		return absConstraint;
	}
	
	public Object getResult(){
		return htVec;
	}
	
	public Object getStackSynt(){
		return stackSynt;
	}
	
	public String getErrosConstraint() {
		Enumeration<String> values = htErrors.keys();
		String value;
		String str = "";
		
		while(values.hasMoreElements()) { 
			value = (String) values.nextElement(); 
			for(String item : htErrors.get(value))
				str += "[" + value + "]: " + item + "\n"; 
		} 			
		
		return str;
	}
	
	public String printConfigurationSet(Object configurationSet){
		
		ConfigurationSet cs = (ConfigurationSet) configurationSet;
		String confFsa = new String("{");
		
		for (Configuration c : cs){
			confFsa = confFsa + c.getFsa().toString();
			confFsa = confFsa + c.getState().toString();
			confFsa = confFsa + ",";
		}
		
		confFsa = confFsa + "}";
		//System.out.println(confFsa);
		
		return confFsa;
	}	
}
